package com.frank.oj.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.nacos.common.utils.IPUtil;
import com.frank.model.entity.user.Role;
import com.frank.model.entity.user.Session;
import com.frank.oj.common.exception.StatusAccessDeniedException;
import com.frank.oj.common.exception.StatusFailException;
import com.frank.oj.constant.Constants;
import com.frank.oj.model.dto.LoginDTO;
import com.frank.oj.model.vo.UserInfoVO;
import com.frank.oj.model.vo.UserRolesVO;
import com.frank.oj.service.entity.user.SessionEntryService;
import com.frank.oj.service.entity.user.UserRoleEntityService;
import com.frank.oj.shiro.AccountProfile;
import com.frank.oj.utils.IpUtils;
import com.frank.oj.utils.JwtUtils;
import com.frank.oj.utils.RedisUtils;
import org.apache.catalina.security.SecurityUtil;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author frank
 * @Date 2024/3/27
 */
@Component
public class AdminAccountManager {
    @Resource
    private SessionEntryService sessionEntryService;
    @Resource
    private JwtUtils jwtUtils;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private UserRoleEntityService userRoleEntityService;

    public UserInfoVO login(LoginDTO loginDto) throws StatusFailException, StatusAccessDeniedException {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpServletResponse response = requestAttributes.getResponse();

        String userIpAddr = IpUtils.getUserIpAddr(request);
        String key = Constants.Account.TRY_LOGIN_NUM.getCode() + loginDto.getUsername() + "_" + userIpAddr;
        Integer count = (Integer) redisUtils.get(key);

        if (count != null && count >= 10) {
            throw new StatusFailException("对不起！当前登录失败次数过多，您的账号可能存在风险，将封锁30分钟，请稍后重试！");
        }
        UserRolesVO userRoles = userRoleEntityService.getUserRoles(null, loginDto.getUsername());

        if (userRoles == null) {
            throw new StatusFailException("用户名不存在 😐");
        }

        if (userRoles.getStatus() != 0) {
            throw new StatusFailException("当前账户存在违规，已对其进行封禁！请联系管理员进行处理 🤡");
        }

        if (!userRoles.getPassword().equals(SecureUtil.md5(loginDto.getPassword()))) {
            if (count == null) {
                redisUtils.set(key, 1, 30 * 60);
            } else {
                redisUtils.set(key, count + 1, 30 * 60);
            }
            throw new StatusFailException("密码错误🤷‍♂️");
        }

        if (count != null) {
            redisUtils.del(key);
        }

        List<String> roleList = new ArrayList<>();
        userRoles.getRoles().forEach(role -> {
            roleList.add(role.getRole());
        });

        if (roleList.contains("admin") || roleList.contains("root") || roleList.contains("problem_admin")) {
            String jwt = jwtUtils.generateToken(userRoles.getUid());
            response.setHeader("Authorization", jwt);
            response.setHeader("Access-Control-Expose-Headers", "Authorization");

            sessionEntryService.save(new Session().setUid(userRoles.getUid())
                    .setIp(IpUtils.getUserIpAddr(request))
                    .setUserAgent(request.getHeader("User-Agent")));
            // 异地登录检验
            sessionEntryService.checkRemoteLogin(userRoles.getUid());

            UserInfoVO userInfo = new UserInfoVO();
            BeanUtil.copyProperties(userRoles, userInfo, "roles");
            userInfo.setRoleList(userRoles.getRoles().stream().map(Role::getRole).collect(Collectors.toList()));

            return userInfo;
        } else {
            throw new StatusAccessDeniedException("小子，别打坏主意😏 当前账户无权限进入后台系统！");
        }

    }

    public void logout() {
        AccountProfile userRole = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        jwtUtils.cleanToken(userRole.getUid());
        SecurityUtils.getSubject().logout();
    }
}
